﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using XRpgLibrary;
using XRpgLibrary.TileEngine;
using XRpgLibrary.SpriteClasses;
using EyesOfTheDragon.Events;
using EyesOfTheDragon.Attacks;
using EyesOfTheDragon.Components;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Audio;
using XRpgLibrary.Events;
using Anthem.GameScreens;
using EyesOfTheDragon.Globals;

namespace Anthem.Components
{
    public class Player:IUpdate,IDraw , IDestroy, IPauseable
    {
        #region Field Region
        Camera camera;
        Game1 gameRef;
        AnimatedSprite animSprite;

        public const string PlayerKilled = "Player_Killed";
        public int Health = 100;
        bool enabled = false;
        public int PlayerLevel = 1;
        public static Player Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new Player(GamePlayScreen.Instance.GameRef);
                    _instance.init();

                }
                return _instance;
            }
        }
        private static Player _instance;
        private const string triggersLayer = "triggersLayer";
        private const int collisoinTileGid = 249;
        #endregion
        public bool Enabled
        {
            get { return enabled; }
            set { enabled = value; }
        }
        #region Property Region
        public Camera Camera
        {
            get { return camera; }
            set { camera = value; }
        }
        public AnimatedSprite Sprite
        {
            get { return animSprite; }
            set { animSprite = value; }
        }

        public bool Vulnerable
        {
            get
            {
                if (attackingWithBat || attackElapsed > 0)
                    return false;
                return true;
            }
        }

     //   public 
        #endregion
        #region Constructor Region
        public void init()
        {
            Texture2D runAnimation = gameRef.Content.Load<Texture2D>(
                @"PlayerSprites\malefighter");
            Texture2D attackAnimation = gameRef.Content.Load<Texture2D>(
                @"PlayerSprites\MC_attacking_baseball_bat");
            Texture2D knifeAnimation = gameRef.Content.Load<Texture2D>(
                   @"PlayerSprites\MC_attacking_knife");
            Texture2D die_texture = gameRef.Content.Load<Texture2D>(
                       @"PlayerSprites\MC_collapsing");
            Dictionary<AnimationKey, Animation> animations = new Dictionary<AnimationKey, Animation>();
            Animation animation = new Animation(4, 53, 106, 0, 0);
            animation.Texture = runAnimation;
            animations.Add(AnimationKey.Down, animation);
            animation = new Animation(4, 53, 106, 0, 106);
            animation.Texture = runAnimation;
            animations.Add(AnimationKey.Left, animation);
            animation.Texture = runAnimation;
            animation = new Animation(4, 53, 106, 0, 212);
            animation.Texture = runAnimation;
            animations.Add(AnimationKey.Right, animation);
            animation = new Animation(4, 53, 106, 0, 318);
            animation.Texture = runAnimation;
            animations.Add(AnimationKey.Up, animation);
            animation = new Animation(4, 106, 106, 0, 106);
            animation.Texture = attackAnimation;
            animations.Add(AnimationKey.AttackLeft, animation);
            animation = new Animation(4, 106, 106, 0, 212);
            animation.Texture = attackAnimation;
            animations.Add(AnimationKey.AttackRight, animation);
            animation = new Animation(4, 106, 106, 0, 106);
            animation.Texture = knifeAnimation;
            animations.Add(AnimationKey.KnifeLeft, animation);
            animation = new Animation(4, 106, 106, 0, 212);
            animation.Texture = knifeAnimation;
            animations.Add(AnimationKey.KnifeRight, animation);

            animation = new Animation(4, 106, 106, 0, 212);
            animation.Texture = die_texture;
            animation.Loops = false;
            animations.Add(AnimationKey.Die, animation);
            Sprite = new AnimatedSprite(runAnimation, animations);
            UpdateList.Instance.add(this);
            
            DrawList.Instance.add(Sprite);
            Sprite.Scale = new Vector2(.5f, .5f);
            enabled = true;
        }
        public void destroy()
        {
            UpdateList.Instance.remove(this);
            DrawList.Instance.remove(Sprite);
            _instance = null;
        }
        public Player(Game game)
        {
            gameRef = (Game1)game;
            camera = new Camera(gameRef.ScreenRectangle);
        }
        public Rectangle getRect()
        {
            return Sprite.getRect();
        }
        #endregion
        #region Method Region
        public void Update(GameTime gameTime)
        {
            if (dying)
            {
                dieElapsed += gameTime.ElapsedGameTime.Milliseconds / 1000f;
                animSprite.Update(gameTime);
                animSprite.IsAnimating = true;
                if (dieElapsed > 1.2f)
                {
                    GamePlayScreen.Instance.KillPlayer();
                    dieElapsed = 0;
                   
                }
                return;
            }
            else if (Health <= 0)
            {
                dying = true;
                dieElapsed = 0;
                animSprite.CurrentAnimation = AnimationKey.Die;
                animSprite.IsAnimating = true;
                animSprite.Update(gameTime);
            }
            fireElapsed -= gameTime.ElapsedGameTime.Milliseconds/1000f;
            attackElapsed -= gameTime.ElapsedGameTime.Milliseconds / 1000f;
            if (attackingWithBat == true && attackElapsed < 0)
            {
                attackingWithBat = false;
                bool left = false;
                if (animSprite.CurrentAnimation == AnimationKey.AttackLeft)
                    left = true;

                if (left)
                {
                    animSprite.Position += new Vector2(73 * map.Instance.MapScale, 0);
                    animSprite.CurrentAnimation = AnimationKey.Left;
                }
                else
                {
                    animSprite.CurrentAnimation = AnimationKey.Right;
                }
                animSprite.IsAnimating = false;
            }
            else if (attackingWithBat == true)
            {
                animSprite.IsAnimating = true;
                animSprite.Update(gameTime);
                if (attackElapsed < .5f)
                {
                    Rectangle ourRect = animSprite.getRect();
                    foreach (MonsterSprite ms in Monster.Instance.Monsters)
                    {
                        if (!ms.Enabled)
                            continue;
                        if (ourRect.Intersects(ms.getRect))
                        {
                            if (ms as FinalBoss == null)
                                ms.Kill();
                            else
                                (ms as FinalBoss).Damage(34, true);
                        }
                    }
                }
                return;
            }

            if (attackingWithKnife == true && attackElapsed < 0)
            {
                attackingWithKnife = false;
                bool left = false;
                if (animSprite.CurrentAnimation == AnimationKey.KnifeLeft)
                    left = true;

                if (left)
                {
                    animSprite.Position += new Vector2(73 * map.Instance.MapScale, 0);
                    animSprite.CurrentAnimation = AnimationKey.Left;
                }
                else
                {
                    animSprite.CurrentAnimation = AnimationKey.Right;
                }
                animSprite.IsAnimating = false;
            }
            else if (attackingWithKnife == true)
            {
                animSprite.IsAnimating = true;
                animSprite.Update(gameTime);
                
                return;
            }
         //   camera.Update(gameTime);
            /*
            if (InputHandler.KeyReleased(Keys.I))
            {
                Camera.ZoomIn();
                if (Camera.CameraMode == CameraMode.Follow)
                    Camera.LockToSprite(animSprite);
            }
            else if (InputHandler.KeyReleased(Keys.O))
            {
                Camera.ZoomOut();
                if (Camera.CameraMode == CameraMode.Follow)
                    Camera.LockToSprite(animSprite);

            }
             * */
            Vector2 motion = Vector2.Zero;
            if (InputHandler.KeyDown(Keys.W) || InputHandler.KeyDown(Keys.Up))
            {
                animSprite.CurrentAnimation = AnimationKey.Up;
                motion.Y = -1;
            }
            else if (InputHandler.KeyDown(Keys.S) || InputHandler.KeyDown(Keys.Down))
            {
                animSprite.CurrentAnimation = AnimationKey.Down;
                motion.Y = 1;
            }
            if (InputHandler.KeyDown(Keys.A) || InputHandler.KeyDown(Keys.Left))
            {
                animSprite.CurrentAnimation = AnimationKey.Left;
                motion.X = -1;
            }
            else if (InputHandler.KeyDown(Keys.D) || InputHandler.KeyDown(Keys.Right))
            {
                animSprite.CurrentAnimation = AnimationKey.Right;
                motion.X = 1;
            }
            if (InputHandler.KeyDown(Keys.Space))
            {
                Fire(); 
            }
            if (InputHandler.KeyDown(Keys.B))
            {
                if (animSprite.CurrentAnimation != AnimationKey.Left && animSprite.CurrentAnimation != AnimationKey.Right)
                    return;
                Bat();
            }
            if (motion != Vector2.Zero)
            {
                animSprite.IsAnimating = true;
                motion.Normalize();
                animSprite.Position += motion * animSprite.Speed;
                animSprite.LockToMap(map.Instance.width*map.Instance.tilewidth -(animSprite.Width*animSprite.Scale.X), map.Instance.height*map.Instance.tileheight-(animSprite.Height*animSprite.Scale.Y));
                if (Camera.CameraMode == CameraMode.Follow)
                    Camera.LockToSprite(animSprite);
                clampCollision();
                animSprite.Update(gameTime);
            }
            else
            {
                animSprite.IsAnimating = false;
            }
            if (InputHandler.KeyReleased(Keys.F))
            {
                Camera.ToggleCameraMode();
                if (Camera.CameraMode == CameraMode.Follow)
                    Camera.LockToSprite(animSprite);
            }
            if (Camera.CameraMode != CameraMode.Follow)
            {
                if (InputHandler.KeyReleased(Keys.C))
                {
                    Camera.LockToSprite(animSprite);
                }
            }
            
        }
        public void clampCollision()
        {
            List<GTile> collisionTiles = map.Instance.getLayer("triggersLayer").getTiles(MapVariables.CollisionGID);
            Rectangle us = getRect();
            foreach (GTile t in collisionTiles)
            {
                if (us.Intersects(t.RectPosition))
                {
                    float leftToRight = Math.Abs(us.Left - t.RectPosition.Right);
                    float rightToLEft = Math.Abs(us.Right - t.RectPosition.Left);
                    float topToBottom = Math.Abs(us.Top - t.RectPosition.Bottom);
                    float bottomToTop = Math.Abs(us.Bottom - t.RectPosition.Top);
                    float xNorm = rightToLEft;
                    float yNorm = bottomToTop;
                    bool leftToRightCalc = false;
                    bool topToBottomCalc = false;
                    if (leftToRight < rightToLEft)
                    {
                        xNorm = leftToRight;
                        leftToRightCalc = true;
                    }
                    if (topToBottom < bottomToTop)
                    {
                        yNorm = topToBottom;
                        topToBottomCalc = true;
                    }
                    bool xNormCalc = false;
                    if (xNorm < yNorm)
                        xNormCalc = true;
                    if (xNormCalc)
                    {
                        if (leftToRightCalc)
                            animSprite.Position += new Vector2(xNorm,0);
                        else
                            animSprite.Position -= new Vector2(xNorm,0);
                    }
                    else
                    {
                        if (topToBottomCalc)
                            animSprite.Position += new Vector2(0, yNorm);
                        else
                            animSprite.Position -= new Vector2(0, yNorm);
                    }
                   
                    us = getRect();
                }
            }
        }
        public void Bat()
        {
            if (attackingWithBat ||  attackingWithKnife)
                return;
            SoundEffect soundFromFile = gameRef.Content.Load<SoundEffect>(@"Sound\hit");
            soundFromFile.Play();
            if (animSprite.CurrentAnimation == AnimationKey.Left)
            {
               
                animSprite.CurrentAnimation = AnimationKey.AttackLeft;
                animSprite.Position -= new Vector2(73 * map.Instance.MapScale, 0); ;
            }
            else
                animSprite.CurrentAnimation = AnimationKey.AttackRight;

            attackElapsed = 1;
            attackingWithBat = true;
            animSprite.Velocity = Vector2.Zero;
            animSprite.IsAnimating = true;
        }
        public void Fire()
        {
            if (attackingWithBat || attackingWithKnife)
                return;

          
            BulletAttack ba = new BulletAttack(gameRef);
            
            switch (animSprite.CurrentAnimation)
            {
                case AnimationKey.Up:
                    ba.Velocity = new Vector2(0, -1);
                    break;
                case AnimationKey.Down:
                    ba.Velocity = new Vector2(0, 1);
                    break;
                case AnimationKey.Left:
                    ba.Velocity = new Vector2(-1, 0);
                    break;
                case AnimationKey.Right:
                    ba.Velocity = new Vector2(1, 0);
                    break;
                default:
                    return;
            }
            ba.init();
            ba.Velocity *= 150;
            ba.Position = animSprite.Position;

            fireElapsed = .5f;
       

            SoundEffect soundFromFile = gameRef.Content.Load<SoundEffect>(@"Sound\hit");
            soundFromFile.Play();
            if (animSprite.CurrentAnimation == AnimationKey.Left)
            {

                animSprite.CurrentAnimation = AnimationKey.KnifeLeft;
                animSprite.Position -= new Vector2(73 * map.Instance.MapScale, 0); ;
            }
            else
                animSprite.CurrentAnimation = AnimationKey.KnifeRight;

            attackElapsed = .5f;
            attackingWithKnife = true;
            animSprite.Velocity = Vector2.Zero;
            animSprite.IsAnimating = true;

            
            
        }
        public void Kill()
        {
            EventRouter.Instance.update(PlayerKilled);
          // Instance = null;
            

            DestroyList.Instance.add(this);
        }
        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            
        }
        #endregion

        #region Private Fields
        float fireElapsed = 0;
        float attackElapsed = 0;
        bool attackingWithBat = false;
        bool attackingWithKnife = false;
        bool dying = false;
        float dieElapsed = 0;
        #endregion
    }
}